package com.sponge.service;

import com.sponge.bean.entity.CreditUser;
import com.sponge.constant.ContractConstant;
import com.sponge.dao.imp.CreditEntityDaoImpl;
import com.sponge.result.ApiError;
import com.sponge.result.SpongeException;
import com.sponge.utils.MathUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.web3j.crypto.CipherException;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.WalletUtils;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.response.EthGetBalance;
import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.tx.Transfer;
import org.web3j.utils.Convert;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.nio.file.Paths;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;

@Service
public class CreditEntityService {

    private static Credentials adminCredentials;
    private List<CreditUser> creditUserList = new ArrayList<>();

    @Autowired
    private MathUtils mathUtils = new MathUtils();

    @Autowired
    private CreditEntityDaoImpl creditEntityDao;

    @Autowired
    private Web3j web3j;

    private Credentials getAdminCredentials() throws IOException, CipherException {
        if (null == adminCredentials) {
            adminCredentials = WalletUtils.loadCredentials(ContractConstant.ADMIN_PASSWORD, ContractConstant.KEYSTORE_FILE);
        }
        return adminCredentials;
    }

    public String createAccount(String username, String password) throws SpongeException {
        try {
            StringBuffer contractPassword = new StringBuffer();
            contractPassword.append(ContractConstant.USER_PASSWORD_PREFIX).append(username).append(password);
            String fileName = WalletUtils.generateNewWalletFile(contractPassword.toString(), new File(ContractConstant.CONTRACT_KEYSTORE_DIR), false);
            Credentials credentials = WalletUtils.loadCredentials(contractPassword.toString(), Paths.get(ContractConstant.CONTRACT_KEYSTORE_DIR,fileName).toString());
            long addTime = System.currentTimeMillis();
//            CreditUser tokenUser = new CreditUser(creditUserList.size(), mathUtils.getFixedLengthNumberByChar(GlobalConstant.USER_ID_LENGTH),username,password,contractPassword.toString(),credentials.getAddress(),credentials.getEcKeyPair().getPrivateKey().toString(),credentials.getEcKeyPair().getPrivateKey().toString(),fileName,0,addTime,addTime);
//            creditUserList.add(tokenUser);
//            creditEntityDao.insertTokenUser(username,password,credentials,fileName);
            return credentials.getAddress();
        } catch (CipherException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        }
        throw new SpongeException(ApiError.UNKNOWN_ERROR);
    }

    public BigInteger getNonce(String address) throws ExecutionException, InterruptedException {
        EthGetTransactionCount ethGetTransactionCount = web3j.ethGetTransactionCount(address, DefaultBlockParameterName.LATEST).sendAsync().get();
        return ethGetTransactionCount.getTransactionCount();
    }

    public BigDecimal getBalance(String address) throws SpongeException {
        try {
            EthGetBalance ethGetBalance = web3j.ethGetBalance(address, DefaultBlockParameterName.LATEST).send();
            if (ethGetBalance.getBalance().toString().equals("0")){
                return new BigDecimal("0");
            }else {
                BigDecimal balance = new BigDecimal(ethGetBalance.getBalance().divide(new BigInteger("10000000000000")).toString());
                BigDecimal ether_balance = balance.divide(new BigDecimal("100000"), 8, RoundingMode.DOWN);
                return ether_balance;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        throw new SpongeException(ApiError.UNKNOWN_ERROR);
    }

    public void sendTransaction(String address, String value, String password, String keystore) throws Exception {
        Credentials credentials = WalletUtils.loadCredentials(password, keystore);
        TransactionReceipt transactionReceipt = Transfer.sendFunds(web3j, credentials, address, new BigDecimal(value), Convert.Unit.ETHER).send();
    }


    //转帐虚拟货币
    public boolean transferToken(String address,String value) throws SpongeException {
//        CreditUser creditUser = null;
//        for (CreditUser user : creditUserList) {
//            if (user.getAddress().equals(address)){
//                creditUser = user;
//                break;
//            }
//        }
//        if (null != creditUser){
//            try {
//                BigDecimal etherValue = new BigDecimal(value).divide(new BigDecimal(ContractConstant.SPONGE_TOKEN_EXCHANGE_RATE), 8, RoundingMode.DOWN);
//                Credentials userCredential = WalletUtils.loadCredentials(creditUser.getContractPassword(), Paths.get(ContractConstant.CONTRACT_KEYSTORE_DIR, creditUser.getKeystoreFile()).toString());
//                TransactionReceipt transactionReceiptEther = Transfer.sendFunds(web3j, userCredential, ContractConstant.CREATOR_ADDRESS, etherValue, Convert.Unit.ETHER).send();
//                LogUtil.info(SpongeTokenService.class,"transactionReceipt.getStatus()==" + transactionReceiptEther.getStatus());
//                if (transactionReceiptEther.getStatus().equals("0x1")){
//                    Credit_sol_Credit spongeToken = Credit_sol_Credit.load(ContractConstant.CONTRACT_ADDRESS, web3j, getAdminCredentials(), ManagedTransaction.GAS_PRICE, Contract.GAS_LIMIT);
//                    TransactionReceipt transactionReceiptToken = spongeToken.transfer(address, new BigInteger(value)).send();
//                    String status = transactionReceiptToken.getStatus();
//                    LogUtil.info(SpongeTokenService.class,"transactionReceiptToken.getStatus()==" + transactionReceiptToken.getStatus());
//                    if (transactionReceiptToken.getStatus().equals("0x1")){
//                        return true;
//                    }else{
//                        return false;
//                    }
//                }else {
//                    return false;
//                }
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//        }else{
//            throw new SpongeException(ApiError.NOT_EXIST_USER);
//        }
        return false;
    }

    public BigInteger queryToken(String address) throws SpongeException {
        try {
            Credentials credentials = getAdminCredentials();
//            Credit_sol_Credit spongeToken = Credit_sol_Credit.load(ContractConstant.CONTRACT_ADDRESS, web3j, credentials, ManagedTransaction.GAS_PRICE, Contract.GAS_LIMIT);
//            spongeToken.setGasProvider(new DefaultGasProvider(){
//                @Override
//                public BigInteger getGasPrice(String contractFunc) {
//                    return super.getGasPrice(contractFunc);
//                }
//
//                @Override
//                public BigInteger getGasLimit(String contractFunc) {
//                    return super.getGasLimit(contractFunc);
//                }
//
//
//            });

//            BigInteger tokenCount = 0;
//                    = spongeToken.balanceOf(address).send();
//            BigInteger tokenCount2 = spongeToken.balanceOf(address).sendAsync().get();
            return null;
        } catch (Exception e) {
            e.printStackTrace();
        }
        throw new SpongeException(ApiError.UNKNOWN_ERROR);
    }



    public CreditUser getTokenUserByAddress(String address){
        for (CreditUser creditUser : creditUserList) {
            if (creditUser.getAddress().equals(address)){
                return creditUser;
            }
        }
        return null;
    }

    public void test(){
//        Credentials.create()
//        RawTransaction rawTransaction = RawTransaction.createTransaction();
//        byte[] bytes = TransactionEncoder.signMessage();

//        Greeter greeter = new Greeter(...);
//        greeter.setGasProvider(new DefaultGasProvider() {
//            @Override
//            public BigInteger getGasPrice(String contractFunc) {
//                switch (contractFunc) {
//                    case Greeter.FUNC_GREET: return BigInteger.valueOf(22_000_000_000L);
//                    case Greeter.FUNC_KILL: return BigInteger.valueOf(44_000_000_000L);
//                    default: throw new NotImplementedException();
//                }
//            }
//
//            @Override
//            public BigInteger getGasLimit(String contractFunc) {
//                switch (contractFunc) {
//                    case Greeter.FUNC_GREET: return BigInteger.valueOf(4_300_000);
//                    case Greeter.FUNC_KILL: return BigInteger.valueOf(5_300_000);
//                    default: throw new NotImplementedException();
//                }
//            }
//        });

    }
}
